#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <mutex>
#include <cassert>
#include <mysql/mysql.h>
#include "../comm/log.hpp"
#include "../comm/util.hpp"

// oj_model.hpp 提供数据交互访问题目的模块功能
namespace NS_Model
{
    using namespace NS_Log;
    using namespace NS_Util;

    struct Question
    {
        std::string _number;     // 题目编号
        std::string _title;      // 题目标题
        std::string _desc;       // 题目描述
        std::string _difficulty; // 题目难度 简单 中等 困难

        std::string _header;     // 题目的预设代码
        std::string _tail;       // 题目的测试用例

        int _cpu_limit;          // 题目的时间要求
        int _mem_limit;          // 题目的空间要求
    };

    const char* tb_name = "problems";
    const char* host    = "127.0.0.1";
    const char* user    = "oj";
    const char* passwd  = "oj123456";
    const char* db_name = "oj";
    const int   port    = 3306;

    //MYSQL* _mysql_conn = nullptr;
    class Model
    {
    private:
        std::mutex mtx;
        MYSQL* _mysql_conn = nullptr;

    public:
        Model()
        {
            if (_mysql_conn == nullptr)
            {
                std::lock_guard<std::mutex> lck(mtx);
                if (_mysql_conn == nullptr)
                {
                    _mysql_conn = mysql_init(nullptr);

                    // 连接数据库
                    if (mysql_real_connect(_mysql_conn, host, user, passwd, db_name, port, nullptr, 0) == nullptr)
                        LOG(FATAL) << "connect mysql failed\n";
                    else
                        LOG(INFO) << "connect mysql success\n";

                    mysql_set_character_set(_mysql_conn, "utf8");
                }
            }
        }

        ~Model()
        {
            mysql_close(_mysql_conn);
        }

        bool QueryMysql(const std::string& sql, std::vector<Question>* out)
        {
            if (mysql_query(_mysql_conn, sql.c_str()) != 0)
            {
                LOG(WARNING) << sql << " execute error\n";
                return false;
            }

            // 提取结果
            MYSQL_RES* res = mysql_store_result(_mysql_conn);

            int rows = mysql_num_rows(res);   // 行数
            for (int i = 0; i < rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);

                Question q;
                q._number     = row[0];
                q._title      = row[1];
                q._difficulty = row[2];
                q._desc       = row[3];
                q._header     = row[4];
                q._tail       = row[5];
                q._cpu_limit  = atoi(row[6]);
                q._mem_limit  = atoi(row[7]);

                out->push_back(q);
            }

            mysql_free_result(res);
            return true;
        }

        bool GetAllQuestions(std::vector<Question>* out)
        {
            std::string sql = "select * from " + std::string(tb_name);
            return QueryMysql(sql, out);
        }

        bool GetOneQuestion(const std::string& number, Question* question)
        {
            std::vector<Question> res;
            std::string sql = "select * from " + std::string(tb_name) + " where number=" + number;
            if (QueryMysql(sql, &res))
            {
                if (res.size() == 1)
                    *question = res[0];
                else
                    return false;
            }
            return true;
        }
    };

}
